using System;
using System.Collections;
using System.Collections.Generic;

namespace Me.Prettyprint.Cassandra.Utils
{
	/// <summary>
	/// For now we take the simplest approach to buffering
    /// the bytes in a List<byte[]>. Later on we can port
    /// Java's ByteBuffer to C#.
	/// </summary>
	public class ByteBufferOutputStream : System.IO.Stream
	{
        private List<ByteBuffer> buffers = null;

        public ByteBufferOutputStream()
        {
            buffers = new List<ByteBuffer>();
        }
        public List<ByteBuffer> GetBufferList()
        {
            return buffers;
        }
        public ByteBuffer GetAllBytes()
        {
            long size = 0;
            foreach (ByteBuffer buff in buffers)
            {
                size += buff.Length;
            }
            byte[] allbytes = new byte[size];
            long offset = 0;
            foreach (ByteBuffer buff in buffers)
            {
                Array.Copy(buff.GetBuffer(), 0, allbytes, offset, buff.Length);
                offset += buff.Length;
            }
            return new ByteBuffer(allbytes);
        }
        public void PrePend(byte[] bytes)
        {
            buffers.Insert(0, new ByteBuffer(bytes));
        }
        public void Append(byte[] bytes)
        {
            buffers.Add(new ByteBuffer(bytes));
        }
        public void PrePend(ByteBuffer buffer)
        {
            buffers.Insert(0, buffer);
        }
        public void Append(ByteBuffer buffer)
        {
            buffers.Add(buffer);
        }
        public void Reset()
        {
            buffers.Clear();
        }
        private ByteBuffer GetBufferWithCapacity(int size)
        {
            ByteBuffer newBuffer = new ByteBuffer(size);
            buffers.Add(newBuffer);
            return newBuffer;
        }
        private void AddBytes(byte[] value)
        {
            if (buffers == null)
            {
                buffers = new List<ByteBuffer>();
            }
            buffers.Add(new ByteBuffer(value));
        }
        public void WriteByte(byte value)
        {
            byte[] buffer = new byte[] { value };
            AddBytes(buffer);
        }
        public void Write(int value)
        {
            byte[] buffer = ConvertToBigEndianBytes(BitConverter.GetBytes(value));
            AddBytes(buffer);
        }
        public void WriteShort(short value)
        {
            byte[] buffer = ConvertToBigEndianBytes(BitConverter.GetBytes(value));
            AddBytes(buffer);
        }
        public void WriteChar(char value)
        {
            byte[] buffer = BitConverter.GetBytes(value);
            AddBytes(buffer);
        }
        public void WriteInt(int value)
        {
            byte[] buffer = ConvertToBigEndianBytes(BitConverter.GetBytes(value));
            AddBytes(buffer);
        }
        public void WriteFloat(float value)
        {
            byte[] buffer = ConvertToBigEndianBytes(BitConverter.GetBytes(value));
            AddBytes(buffer);
        }
        public void WriteDouble(double value)
        {
            byte[] buffer = ConvertToBigEndianBytes(BitConverter.GetBytes(value));
            AddBytes(buffer);
        }
        public void WriteLong(long value)
        {
            byte[] buffer = ConvertToBigEndianBytes(BitConverter.GetBytes(value));
            AddBytes(buffer);
        }
        public void Write(byte[] value)
        {
            AddBytes(value);
        }
        public void WriteByteBuffer(ByteBuffer buffer)
        {
            ByteBuffer dup = buffer.Duplicate();
            dup.Position = buffer.Length;
            buffers.Add(dup);
        }
        public override void Write(byte[] bytes, int offset, int count)
        {
            throw new NotImplementedException();
        }
        public override int Read(byte[] bytes, int offset, int count)
        {
            throw new NotImplementedException();
        }
        public override void SetLength(long value)
        {
            throw new NotImplementedException();
        }
        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            throw new NotImplementedException();
        }
        public override void Flush()
        {
            throw new NotImplementedException();
        }
        public override long Position
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
        public override long Length
        {
            get { throw new NotImplementedException(); }
        }
        public override bool CanWrite
        {
            get { return false; }
        }
        public override bool CanSeek
        {
            get { return false; }
        }
        public override bool CanRead
        {
            get { throw new NotImplementedException(); }
        }
        public byte[] ConvertToBigEndianBytes(byte[] bytes)
        {
            byte[] clone = (byte[])bytes.Clone();
            if (System.BitConverter.IsLittleEndian)
            {
                Array.Reverse(clone);
                return clone;
            }
            return bytes;
        }
        public byte[] ConvertFromBigEndianBytes(byte[] bytes)
        {
            byte[] clone = (byte[])bytes.Clone();
            if (System.BitConverter.IsLittleEndian)
            {
                Array.Reverse(clone);
                return clone;
            }
            return bytes;
        }
    }
}